﻿#region Using

using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using XNgine.Services;
using XNgine.Threading;

#endregion

namespace XNgine.ScreenManagement.StandardScreens
{
    public class LoadingScreen : GameScreen
    {
        public delegate void AditinalLoadingMethod(ThreadedLoader loader);

        /// <summary>
        /// This is a method delegate called after the Screen.LoadContent() for each screen is finished;
        /// </summary>
        public AditinalLoadingMethod AdditionalLoading;

        public const string SCREEN_NAME = "XNGine.LoadingScreen";

        /// <summary>  
        /// A default font for menu titles
        /// </summary>  
        public static SpriteFont Font { get; set; }

        private bool loadingStarted;
        private readonly bool loadingIsSlow;
        private readonly bool removeAllOtherScreens;
        private readonly IGameScreen[] screensToLoad;

        private readonly ThreadedLoader loader;

        //private LoadingScreen(params GameScreen[] screensToLoad) : this(false, false, screensToLoad) { }
        public LoadingScreen(bool loadingIsSlow, bool removeAllOtherScreens, params IGameScreen[] screensToLoad)
            : base(SCREEN_NAME)
        {
            BlocksUpdate = true;
            BlocksDraw = true;
            BlocksInput = true;

            this.loadingIsSlow = loadingIsSlow;
            this.screensToLoad = screensToLoad;
            this.removeAllOtherScreens = removeAllOtherScreens;

            loader = new ThreadedLoader(Load);
            loader.ExecutionFinished += loader_ExecutionFinished;
            loader.Max = screensToLoad.Length;
        }

        private void loader_ExecutionFinished(object sender, EventArgs e)
        {
            IScreenManagement sm = XEngine.Instance.GetService<IScreenManagement>();

            if (removeAllOtherScreens)
                sm.CloseAllScreens(true);
            else
                sm.CloseScreen(this);

            foreach (IGameScreen screen in screensToLoad)
            {
                sm.Show(screen);
            }
        }

        public override void LoadContent()
        {
            if (ContentLoaded) return;
            if (Font == null)
                Font = XEngine.Instance.Content.Load<SpriteFont>("Fonts/menufont");
            ContentLoaded = true;
        }

        /// <summary>
        /// This method is executed by the ThreadedLoader to load all the screens
        /// </summary>
        private void Load(ThreadedExecutor executor)
        {
            foreach (IGameScreen screen in screensToLoad)
            {
                screen.LoadContent();
                loader.Progress++;
            }
            if (AdditionalLoading != null)
                AdditionalLoading(this.loader);
        }

        public static void Load(params IGameScreen[] screensToLoad)
        {
            Load(false, false, screensToLoad);
        }

        public static void Load(bool loadingIsSlow, bool removeAllOtherScreens, params IGameScreen[] screensToLoad)
        {
            XEngine.Instance.GetService<IScreenManagement>().Show(
                new LoadingScreen(loadingIsSlow, removeAllOtherScreens, screensToLoad));
        }

        public override void Update()
        {
            if (!loadingStarted)
            {
                loadingStarted = true;
                loader.StartLoading();
            }
        }

        public override void Draw()
        {
            if (!ContentLoaded) return;

            string message = "Loading...";

            if (loadingIsSlow)
            {
                message = loader.PercentsComplete + "% Loaded";
            }

            // Center the text in the viewport.
            Viewport viewport = XEngine.Instance.GraphicsDevice.Viewport;
            Vector2 viewportSize = new Vector2(viewport.Width, viewport.Height);
            Vector2 textSize = Font.MeasureString(message);
            Vector2 textPosition = (viewportSize - textSize)/2;

            Color color = Color.White;

            XEngine.Instance.SpriteBatch.Begin
                (SpriteBlendMode.AlphaBlend, SpriteSortMode.Deferred, SaveStateMode.SaveState);
            XEngine.Instance.SpriteBatch.DrawString(Font, message, textPosition, color);
            XEngine.Instance.SpriteBatch.End();
        }
    }
}